﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.ComponentModel;

namespace BDSim
{
    public class SendReceiveDevice
    {
        #region 字段        
        private double _Elelim = 5; /// 观测截止仰角(0~30) 调用时需赋值-----------------------------
        private double _Freq = 22784;/// Ka频点            调用时需赋值-----------------------------
        public StationCollection Parent;     //同一类型站集
        public SimParam simParam;
        private ObsReceiverInPut ObsInput;
        private ObsReceiverOutput ObsOutput;

        #region 规划表参量
        List<Linkpair> Linkpairs;
        private int RecID;
        private int SndID;
        int BD_WN;
        double BD_SOW;
        StreamReader sr;
        #endregion

        #region 观测误差配置

        private double[] _DeltRanThH = { 0.0, 0.0 };//噪声量级,_DeltRanThH[0]为伪距噪声； _DeltRanThH[1]为载波相位噪声
        private ObsErrFlagClass _ErrFlag = new ObsErrFlagClass();  
        private ESatClkModelType _SatClkModel;
        private EStaClkModelType _StaClkModel;
        private EIonMappingModelType _IonMappingModel;
        private ETroModelType _TroModelType;
        private EMulModelType _MulModel;
        private ERelModelType _RelModel;
        private EOffModelType _OffModel;
        private RanSet _Ran_Set;

        #endregion

        #endregion 

        #region 属性

        #region 观测信息配置

        [Category("观测信息配置"), Description("截止高度角"), PropertyOrder(2)]
        public double Elelim
        {
            get { return _Elelim; }
            set { _Elelim = value; }
        }

        [Category("观测信息配置"), Description("Ka频点值"), PropertyOrder(1)]
        public double KaFrequency
        {
            get { return _Freq; }
            set { _Freq = value; }
        }

        #region 观测误差配置

        [Category("观测信息配置"), Description("误差控制开关"), PropertyOrder(4)]
        public ObsErrFlagClass ErrFlag
        {
            get { return _ErrFlag; }
            set { _ErrFlag = value; }
        }

        [Category("观测信息配置"), Description("噪声量级，DeltRanThH[0]：伪距噪声量级；DeltRanThH[1]：载波相位噪声量级"), PropertyOrder(3)]
        public double[] DeltRanThH
        {
            get { return _DeltRanThH; }
            set { _DeltRanThH = value; }
        }

        #endregion

        #endregion

        #endregion

        #region 方法

        /// <summary>
        /// 读取星地规划表（一个时隙）
        /// </summary>
        public int ReadSat2StaPlan()
        {
            Linkpairs.Clear();
            string oneline = sr.ReadLine();
            if (oneline == null)
            {
                return -1;
            }

            int NumofPair;
            NumofPair = Int32.Parse(oneline);

            oneline = sr.ReadLine();
            char[] spilt = { ' ', ':', '-', '>', 'S' };
            string[] data = oneline.Split(spilt, StringSplitOptions.RemoveEmptyEntries);
            int BD_Wn1, BD_Wn2;
            double BD_Sow1, BD_Sow2;

            BD_Wn1 = Int32.Parse(data[0]);
            BD_Wn2 = Int32.Parse(data[2]);
            BD_Sow1 = Double.Parse(data[1]);
            BD_Sow2 = Double.Parse(data[3]);
            BD_WN = BD_Wn1;
            BD_SOW = BD_Sow1;

            for (int i = 0; i < NumofPair; i++)
            {
                Linkpair temp = new Linkpair();
                temp.SndID = Int32.Parse(data[2 * i + 4]);
                temp.RecID = Int32.Parse(data[2 * i + 5]);

                Linkpairs.Add(temp);


            }
            return 1;
        }

        /// <summary>
        /// 星地观测数据仿真初始化（Ka）
        /// </summary>
        public int Sat2StaObsInit()
        {
            sr = new StreamReader("..\\..\\仿真场景\\地面控制段\\锚固站\\Sat2StaPlans.dat");
            Linkpairs = new List<Linkpair>();
            simParam.pStartTime = BDSimObject.GlobalStartTime;
            simParam.simClks = 0;
            ObsInput.CurTime = BDSimObject.GlobalStartTime;
            int NumofPair;
            double BD_JD, UTC_JD;
            string[] data;
            do
            {
                string oneline = sr.ReadLine();
                if (oneline == null)
                {
                    return -1;
                }

                NumofPair = Int32.Parse(oneline);
                oneline = sr.ReadLine();
                char[] spilt = { ' ', ':', '-', '>', 'S' };
                data = oneline.Split(spilt, StringSplitOptions.RemoveEmptyEntries);
                int BD_Wn1, BD_Wn2;
                double BD_Sow1, BD_Sow2;

                BD_Wn1 = Int32.Parse(data[0]);
                BD_Wn2 = Int32.Parse(data[2]);
                BD_Sow1 = Double.Parse(data[1]);
                BD_Sow2 = Double.Parse(data[3]);

                BD_WN = BD_Wn1;
                BD_SOW = BD_Sow1;

                TimeSpaceDll.BDT_WnSec2JD(BD_WN, BD_SOW, out BD_JD);
                TimeSpaceDll.BDT2UTC(BD_JD, out UTC_JD);

                ///规划时间超出仿真结束时间
                if (UTC_JD > BDSimObject.GlobalEndTime.JD)
                {
                    return -1;
                }
            } while (UTC_JD < BDSimObject.GlobalStartTime.JD);

            for (int i = 0; i < NumofPair; i++)
            {
                Linkpair temp = new Linkpair();
                temp.SndID = Int32.Parse(data[2 * i + 4]);
                temp.RecID = Int32.Parse(data[2 * i + 5]);
                Linkpairs.Add(temp);
            }
            return 1;
        }

        /// <summary>
        /// 观测数据仿真(双向)
        /// </summary>
        public void Sat2StaObsOutput(string ObsPath)
        {
            TimeSpaceDll.CAL2UTC(out BDSimObject.GlobalStartTime, 1);
            double StartJD = BDSimObject.GlobalStartTime.JD;

            UTCTime tempTime;

            ///规划标志
            int Flag = 1;
            while (Flag == 1)
            {
                for (int i = 0; i < 2; i++)
                {
                    ///建链时间
                    double BD_JD, UTC_JD;
                    TimeSpaceDll.BDT_WnSec2JD(BD_WN, BD_SOW, out BD_JD);

                    TimeSpaceDll.BDT2UTC(BD_JD, out UTC_JD);

                    UTC_JD = UTC_JD + 1.5 / 86400.0;//计算生成观测值时刻——假设生成时刻为测量周期的下降沿

                    ///下一个1.5s
                    if (i == 1)
                    {
                        UTC_JD = UTC_JD + 1.5 / 86400.0;
                    }


                    ///规划时间超出仿真结束时间，停止
                    if (UTC_JD > BDSimObject.GlobalEndTime.JD)
                    {
                        return;
                    }

                    tempTime.JD = UTC_JD;
                    TimeSpaceDll.CAL2UTC(out tempTime, 2);
                    ObsInput.CurTime = tempTime;

                    ObsInput.DeltRanThH = new double[2];
                    ObsInput.DeltRanThH[0] = _DeltRanThH[0];
                    ObsInput.DeltRanThH[1] = _DeltRanThH[1];

                    for (int j = 0; j < Linkpairs.Count; j++)
                    {
                        ObsReceiverOutput obsOutput = new ObsReceiverOutput();

                        ///明确收发卫星对
                        if (i == 0)
                        {
                            RecID = Linkpairs[j].RecID;
                            SndID = Linkpairs[j].SndID;

                            ///地面站为接收站,此时生成下行观测数据
                            if (RecID > 100 && SndID < 100)
                            {
                                DownObsCal(RecID, SndID, ObsInput.CurTime, out obsOutput);
                            }

                            //地面站位发射站，此时生成上行观测数据
                            if (RecID < 100 && SndID > 100)
                            {
                                UpObsCal(SndID, RecID, ObsInput.CurTime, out  obsOutput);
                            }
                        }
                        else
                        {
                            SndID = Linkpairs[j].RecID;
                            RecID = Linkpairs[j].SndID;

                            ///地面站为接收站,此时生成下行观测数据
                            if (RecID > 100 && SndID < 100)
                            {
                                DownObsCal(RecID, SndID, ObsInput.CurTime, out obsOutput);
                            }

                            //地面站位发射站，此时生成上行观测数据
                            if (RecID < 100 && SndID > 100)
                            {
                                UpObsCal(SndID, RecID, ObsInput.CurTime, out  obsOutput);
                            }
                        }

                        int WN;
                        double Sec;
                        double BDT;
                        TimeSpaceDll.UTC2BDT(obsOutput.CurTime.JD, out BDT);
                        TimeSpaceDll.BDT_JD2WnSec(BDT, out  WN, out  Sec);

                        string SndName;
                        string RecName;
                        if (SndID > 100)
                        {
                            SndName = "Station";
                            RecName = "Sat";
                        }
                        else
                        {
                            SndName = "Sat";
                            RecName = "Station";
                        }


                        string SendFilePath = ObsPath + SndName + string.Format("{0:D3}", SndID) + ".txt";
                        string RecFilePath = ObsPath + RecName + string.Format("{0:D3}", RecID) + ".txt";
                        string FileContent = "1  " + WN.ToString().PadLeft(4, ' ') + Sec.ToString("0.00").PadLeft(10, ' ')
                            + " " + string.Format("{0:D2}", SndID) + " " + string.Format("{0:D2}", RecID)
                            + obsOutput.SatObs.A_Pseudo_writein.ToString("0.000000").PadLeft(18, ' ')
                            + obsOutput.SatObs.DotPseudo.ToString("0.000000").PadLeft(18, ' ') + "\r\n";
                        File.AppendAllText(SendFilePath, FileContent);
                        File.AppendAllText(RecFilePath, FileContent);
                    }

                }
                ///读取下一时隙规划，若不存在，则返回
                Flag = ReadSat2StaPlan();
            }
        }

        /// 上行观测数据生成
        private void UpObsCal(int StationID, int SatID, UTCTime NowTime, out ObsReceiverOutput UpObsOutput)
        {
            Satellite Sat;
            ObsReceiverOutput TempObsOutput = new ObsReceiverOutput();
            double ErrValue = 0;

            #region 获取上行观测卫星位置

            SpaceSegment temp = new SpaceSegment();
            temp = (Parent.Parent.Parent.Parent as Scenario).SegmentColletion[0] as SpaceSegment;
            Sat = temp.ConstellationList[0].SatelliteCollection[SatID - 1];

            int SatPVListID = (int)Math.Floor((NowTime.JD - BDSimObject.GlobalStartTime.JD) * 86400.0 / Sat.Orbit.IntegrationParam.StepSize);
            int SendPVListID = SatPVListID;

            NodePosVel RealECIPV = new NodePosVel();
            double trpTime = (NowTime.JD - BDSimObject.GlobalStartTime.JD) * 86400.0; //需要差值的时刻(相对时间，单位秒)
            RealECIPV = CSatelliteDLL.KSGTRP(14, 3, trpTime, Sat.OrbitBackDiffList[SatPVListID]);
            RealECIPV.Epoch = NowTime;

            #endregion

            #region 获取上行观测地面站位置信息(10个点)
            NodePosVel StationECIPos = new NodePosVel(); ;
            NodePosVel StationECFPos = new NodePosVel();


            foreach (var station in Parent.StationList)
            {
                if (station.Id == StationID)
                {
                    ObsInput.SendPos = new NodePosVel[10];

                    StationECFPos.X = station.Pos_XYZ.X;
                    StationECFPos.Y = station.Pos_XYZ.Y;
                    StationECFPos.Z = station.Pos_XYZ.Z;
                    StationECFPos.VX = 0;
                    StationECFPos.VY = 0;
                    StationECFPos.VZ = 0;

                    for (int k = 0; k < 10; k++)
                    {
                        UTCTime Temp;

                        double TempNowTime = (k - 4) * 30;  //30秒一个点
                        Temp.IntJD = ObsInput.CurTime.IntJD + Math.Floor(TempNowTime / 86400.0);
                        Temp.DouJD = ObsInput.CurTime.DouJD + TempNowTime / 86400.0 - Math.Floor(TempNowTime / 86400.0);
                        Temp.JD = Temp.IntJD + Temp.DouJD;
                        TimeSpaceDll.CAL2UTC(out Temp, 2);
                        StationECFPos.Epoch = Temp;

                        TimeSpaceDll.ECF2ECI(StationECFPos, 0, 0, out  ObsInput.SendPos[k]);

                    }
                    break;
                }
            }
  
            #endregion

            ObsInput.StaID = SatID;
            ObsInput.SatID = StationID;
            ObsInput.SendPosFlag = 1;

            /// 单个时刻可见星观测值
            NodePosVel SatOrbECF = new NodePosVel();
            TimeSpaceDll.ECI2ECF(RealECIPV, 0, 0, out  SatOrbECF);

            ObsInput.ReceiverPos = RealECIPV;

            double Ele;
            double Azi;
            if (true)//1 == CAccessCalDLL.StationAccess(StationECFPos, SatOrbECF, ECFtype.type_CGCS2000, _Elelim, out Ele, out Azi))
            {
                //观测误差计算
                #region 误差计算
                if (_ErrFlag.IsSatClk)//卫星钟差
                {

                }
                else
                {
                    ErrValue = 0;
                }


                if (_ErrFlag.IsStaClk)
                {

                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsItro)//对流层误差
                {
                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsImul)
                {

                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsIoff)
                {

                }
                else
                {
                    ErrValue += 0;

                }

                if (_ErrFlag.IsIrel)
                {

                }
                else
                {
                    ErrValue += 0;

                }

                #endregion 误差计算

                ObsInput.Freq = _Freq;

                if (_ErrFlag.IsIion)//电离层误差计算
                {

                }
                else
                {
                    ObsInput.ObsErr = new double[2];
                    ObsInput.ObsErr[0] = ErrValue + 0;
                    ObsInput.ObsErr[1] = ErrValue - 0;
                }

                int aa = CObsDataGenDLL.ObsRecvInit(ObsInput, out TempObsOutput);
            }
            UpObsOutput = TempObsOutput;

        }

        /// 下行观测数据生成
        private void DownObsCal(int StationID, int SatID, UTCTime NowTime, out ObsReceiverOutput DownObsOutput)
        {
            Satellite Sat;
            double ErrValue = 0;

            #region 获取下行观测地面站位置

            NodePosVel StationECIPos = new NodePosVel();
            NodePosVel StationECFPos = new NodePosVel();
            
            foreach (var station in Parent.StationList)
            {
                if (station.Id == StationID)
                {
                    StationECFPos.Epoch = ObsInput.CurTime;
                    StationECFPos.X = station.Pos_XYZ.X;
                    StationECFPos.Y = station.Pos_XYZ.Y;
                    StationECFPos.Z = station.Pos_XYZ.Z;
                    StationECFPos.VX = 0;
                    StationECFPos.VY = 0;
                    StationECFPos.VZ = 0;

                    TimeSpaceDll.ECF2ECI(StationECFPos, 0, 0, out  StationECIPos);
                    ObsInput.ReceiverPos = StationECIPos;
                    break;
                }
            }

            #endregion

            #region 获取下行观测卫星10个点位置信息
            SpaceSegment temp = new SpaceSegment();
            temp = (Parent.Parent.Parent.Parent as Scenario).SegmentColletion[0] as SpaceSegment;
            Sat = temp.ConstellationList[0].SatelliteCollection[SatID - 1];

            NodePosVel[] SatPosMsg = new NodePosVel[10];
            int SatPVListID = (int)Math.Floor((NowTime.JD - BDSimObject.GlobalStartTime.JD) * 86400.0 / Sat.Orbit.IntegrationParam.StepSize);
            int SendPVListID = SatPVListID;
            if (SendPVListID >= 5 & (Sat.OrbitPVList.Count - SendPVListID) > 5)
            {
                for (int len = 0; len < 10; len++)
                {
                    SatPosMsg[len] = Sat.OrbitPVList[SendPVListID - 5 + len].SatPV_ECI;
                }
            }
            else if (SendPVListID < 5)
            {
                for (int len = 0; len < 10; len++)
                {
                    SatPosMsg[len] = Sat.OrbitPVList[len].SatPV_ECI;
                }
            }
            else
            {
                for (int len = 0; len < 10; len++)
                {
                    SatPosMsg[len] = Sat.OrbitPVList[Sat.OrbitPVList.Count - 10 + len].SatPV_ECI;
                }
            }

            #endregion

            ObsInput.StaID = StationID;
            ObsInput.SatID = SatID;
            ObsInput.SendPosFlag = 1;

            ObsInput.SendPos = new NodePosVel[10];
            ObsInput.SendPos = SatPosMsg;

            /// 单个时刻可见星观测值
            NodePosVel SatOrbECF = new NodePosVel();
            TimeSpaceDll.ECI2ECF(ObsInput.SendPos[4], 0, 0, out  SatOrbECF);

            double Ele;
            double Azi;
            ObsReceiverOutput TempObsOutput = new ObsReceiverOutput();
            if (true)//1== CAccessCalDLL.StationAccess(StationECFPos, SatOrbECF, ECFtype.type_CGCS2000, _Elelim, out Ele, out Azi))
            {
                //观测误差计算
                #region 误差计算
                if (_ErrFlag.IsSatClk)//卫星钟差
                {

                }
                else
                {
                    ErrValue = 0;
                }


                if (_ErrFlag.IsStaClk)
                {

                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsItro)//对流层误差
                {
                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsImul)
                {

                }
                else
                {
                    ErrValue += 0;
                }

                if (_ErrFlag.IsIoff)
                {

                }
                else
                {
                    ErrValue += 0;

                }

                if (_ErrFlag.IsIrel)
                {

                }
                else
                {
                    ErrValue += 0;

                }

                #endregion 误差计算

                ObsInput.Freq = _Freq;

                if (_ErrFlag.IsIion)//电离层误差计算
                {

                }
                else
                {
                    ObsInput.ObsErr = new double[2];
                    ObsInput.ObsErr[0] = ErrValue + 0;
                    ObsInput.ObsErr[1] = ErrValue - 0;
                }

                int aa = CObsDataGenDLL.ObsRecvInit(ObsInput, out TempObsOutput);
            }
            DownObsOutput = TempObsOutput;
        }

        #endregion

    }
}
